package com.zijidelu.luframework.starter.scanner.impl;

import com.zijidelu.luframework.base.TypeCaster;
import com.zijidelu.luframework.base.model.DataModel;
import com.zijidelu.luframework.base.model.PO;
import com.zijidelu.luframework.constant.RepositoryConstant;
import com.zijidelu.luframework.infrastructure.converter.DataConverter;
import com.zijidelu.luframework.infrastructure.factory.ConverterVault;
import com.zijidelu.luframework.infrastructure.factory.DataVault;
import com.zijidelu.luframework.infrastructure.persistence.repository.core.bizsig.AbstractBizSigRepository;
import com.zijidelu.luframework.infrastructure.persistence.repository.core.bizsig.BizSigRepository;
import com.zijidelu.luframework.infrastructure.persistence.repository.core.criteria.AbstractBizSigPersistenceContext;
import com.zijidelu.luframework.infrastructure.persistence.repository.core.criteria.AbstractPersistenceContext;
import com.zijidelu.luframework.infrastructure.persistence.repository.core.criteria.BizSigPersistenceContext;
import com.zijidelu.luframework.infrastructure.persistence.repository.core.criteria.PersistenceContext;
import com.zijidelu.luframework.infrastructure.persistence.repository.core.data.AbstractDataRepository;
import com.zijidelu.luframework.infrastructure.persistence.repository.core.data.DataRepository;
import com.zijidelu.luframework.infrastructure.persistence.repository.core.domain.calculator.AbstractDomainKeyCalculator;
import com.zijidelu.luframework.infrastructure.persistence.repository.core.domain.calculator.DomainKeyCalculator;
import com.zijidelu.luframework.starter.scanner.AbstractAutoScanner;
import com.zijidelu.luframework.utils.cache.vault.Vault;
import com.zijidelu.luframework.utils.collection.stream.StreamUtil;
import com.zijidelu.luframework.utils.spring.beans.generic.SpringBeanTypeUtil;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import net.bytebuddy.description.type.TypeDescription;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.ResolvableType;
import org.springframework.stereotype.Component;

import java.util.HashSet;
import java.util.Objects;
import java.util.Set;

/**
 * 数据转换器扫描器。
 *
 * @author ZIJIDELU
 * @datetime 2025/10/20 22:03
 */
@Component
@RequiredArgsConstructor
@Slf4j
public class DataConverterScanner extends AbstractAutoScanner {
    @Setter(onMethod_ = {@Autowired})
    private DataVault dataVault;
    @Setter(onMethod_ = {@Autowired})
    private ConverterVault converterVault;

    @Override
    public Class<? extends AbstractAutoScanner> dependOn() {
        return MybatisPlusServiceScanner.class;
    }

    @Override
    public void start() {
        // 按泛型参数组合去重
        final Set<String> processedTypePairs = new HashSet<>();

        // PDConvert
        StreamUtil.smartStream(getSpringDynamicBeanRegisterUtil().getBeansOfType(DataConverter.class).values())
                .forEach((bean) -> {
                    final ResolvableType beanResolvableType = ResolvableType.forInstance(bean);
                    final Class<?> beanClass = Objects.requireNonNull(beanResolvableType.resolve());
                    final String packageName = beanClass.getPackageName();
                    // 解析泛型参数
                    final ResolvableType[] resolvableTypes = SpringBeanTypeUtil.resolvableTargetClassTypes(bean, DataConverter.class);
                    final Class<PO> poClass = TypeCaster.cast(Objects.requireNonNull(resolvableTypes[0].resolve()));
                    final Class<DataModel> dataModelClass = TypeCaster.cast(Objects.requireNonNull(resolvableTypes[1].resolve()));
                    final String typeKey = Vault.calcItemKeyWithClass(poClass, dataModelClass);
                    // 跳过已处理的类型对
                    if (processedTypePairs.contains(typeKey)) {
                        return;
                    }

                    // 注册数据转换器PO
                    converterVault.registerDataConverter(poClass, TypeCaster.cast(bean));
                    // 注册数据转换器DataModel
                    converterVault.registerDataConverter(dataModelClass, TypeCaster.cast(bean));

                    // 领域键计算器
                    domainKeyCalculatorScanner(packageName, poClass);
                    // 基础持久化上下文
                    persistenceContextScanner(packageName, poClass);
                    // 基础数据仓库
                    final DataRepository<PO, DataModel> dataRepository = dataRepositoryScanner(packageName, poClass, dataModelClass);
                    // 业务签名持久化上下文
                    bizSigPersistenceContextScanner(packageName, poClass, dataModelClass);
                    // 业务签名数据仓库
                    final BizSigRepository<PO, DataModel> bizSigRepository = bizSigRepositoryScanner(packageName, poClass, dataModelClass);

                    // 注册 DataModel 到 Repository 的映射
                    dataVault.registerDataRepository(dataModelClass, dataRepository);

                    // 注册 DataModel 到 BizSigRepository 的映射
                    dataVault.registerBizSigRepository(dataModelClass, bizSigRepository);

                    // 标记为已处理
                    processedTypePairs.add(typeKey);
                });

    }

    /**
     * 数据仓库扫描器。
     *
     * @param packageName    包名
     * @param poClass        实体类
     * @param dataModelClass 数据模型类
     * @return 数据仓库实例
     */
    private <P extends PO, D extends DataModel> DataRepository<P, D> dataRepositoryScanner(String packageName, Class<P> poClass, Class<D> dataModelClass) {
        // DataRepository
        final Object object = genericRegisterBeans(calcUniDomain(dataModelClass, RepositoryConstant.DATA_REPOSITORY_SUFFIX),
                packageName,
                TypeDescription.Generic.Builder.parameterizedType(AbstractDataRepository.class,
                        poClass, dataModelClass
                ).build(),
                TypeDescription.Generic.Builder.parameterizedType(DataRepository.class,
                        poClass, dataModelClass
                ).build()
        );
        return TypeCaster.cast(object);
    }

    /**
     * 领域键计算器扫描器。
     *
     * @param packageName 包名
     * @param poClass     实体类
     * @return 领域键计算器实例
     */
    private Object domainKeyCalculatorScanner(String packageName, Class<?> poClass) {
        // DomainKeyCalculator
        return genericRegisterBeans(calcUniDomain(poClass, RepositoryConstant.DOMAIN_KEY_CALCULATOR_SUFFIX),
                packageName,
                TypeDescription.Generic.Builder.parameterizedType(AbstractDomainKeyCalculator.class, poClass).build(),
                new TypeDescription.ForLoadedType(DomainKeyCalculator.class)
        );
    }

    /**
     * 业务签名仓库扫描器。
     *
     * @param packageName    包名
     * @param poClass        实体类
     * @param dataModelClass 数据模型类
     * @return 业务签名仓库实例
     */
    private <P extends PO, D extends DataModel> BizSigRepository<P, D> bizSigRepositoryScanner(String packageName, Class<P> poClass, Class<D> dataModelClass) {
        // BizSigRepository
        return TypeCaster.cast(genericRegisterBeans(calcUniDomain(dataModelClass, RepositoryConstant.BIZ_SIG_REPOSITORY_SUFFIX),
                packageName,
                TypeDescription.Generic.Builder.parameterizedType(AbstractBizSigRepository.class,
                        poClass, dataModelClass
                ).build(),
                TypeDescription.Generic.Builder.parameterizedType(BizSigRepository.class,
                        poClass, dataModelClass
                ).build()
        ));
    }

    /**
     * 持久化上下文扫描器。
     *
     * @param packageName 包名
     * @param poClass     实体类
     * @return 持久化上下文实例
     */
    private Object persistenceContextScanner(String packageName, Class<?> poClass) {
        // PersistenceContext
        return genericRegisterBeans(calcUniDomain(poClass, RepositoryConstant.PERSISTENCE_CONTEXT_SUFFIX),
                packageName,
                TypeDescription.Generic.Builder.parameterizedType(AbstractPersistenceContext.class, poClass).build(),
                TypeDescription.Generic.Builder.parameterizedType(PersistenceContext.class, poClass).build()
        );
    }

    /**
     * 业务签名持久化上下文扫描器。
     *
     * @param packageName    包名
     * @param poClass        实体类
     * @param dataModelClass 数据模型类
     * @return 业务签名持久化上下文实例
     */
    private Object bizSigPersistenceContextScanner(String packageName, Class<?> poClass, Class<?> dataModelClass) {
        // BizSigPersistenceContext
        return genericRegisterBeans(calcUniDomain(dataModelClass, RepositoryConstant.BIZ_SIG_PERSISTENCE_CONTEXT_SUFFIX),
                packageName,
                TypeDescription.Generic.Builder.parameterizedType(AbstractBizSigPersistenceContext.class,
                        poClass, dataModelClass
                ).build(),
                TypeDescription.Generic.Builder.parameterizedType(BizSigPersistenceContext.class,
                        poClass, dataModelClass
                ).build()
        );
    }
}
